package com.example.demo.aop;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import javax.persistence.Cacheable;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Aspect
@Component
@ConditionalOnProperty(name = "cacheable.check.switch", havingValue = "1")
public class SignAop {

    private static ObjectMapper mapper = new ObjectMapper();

    @Pointcut("execution(* com.example.demo.controller.*.*(..))")
    private void signAop() {
    }


    @Before("signAop()")
    public void before(JoinPoint joinPoint) throws JsonProcessingException {

        System.out.println("接口-------->" + joinPoint.getSignature().getName() + "；" + LocalDateTime.now() + ":");
        System.out.println("入参" + mapper.writeValueAsString(joinPoint.getArgs()));

    }

    @AfterReturning(pointcut = "signAop()", returning = "data")
    public void doAfterReturning(JoinPoint joinPoint, Object data) throws JsonProcessingException {
        System.out.println("出参" + mapper.writeValueAsString(data) + "\n\n");
    }

    //针对每个缓存，都有自己的一个set
    private Map<String, Set<String>> cache = new ConcurrentHashMap<>();
    //存放失效缓存的集合
    private Set<String> unValidCache = new HashSet<>();


    /**
     * 根据注解做切面 判断cacheable缓存是否生效
     */
    @Around("@annotation(cacheable)")
    public Object before(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {
        Object[] args = joinPoint.getArgs();
        String value = String.join("_", String.valueOf(cacheable.value()));
        if (!unValidCache.contains(value)) {
            if (!cache.containsKey(value)) {
                synchronized (cache) {
                    if (!cache.containsKey(value)) {
                        cache.put(value, new HashSet<>());
                    }
                }
            }
            String key = Arrays.stream(args).map(String::valueOf).collect(Collectors.joining("_"));
            Set<String> set = cache.get(value); //同一个缓存同一个key，如果多次调用了，说明缓存失效
            if (set.contains(key)) {
                System.err.println(value + "缓存无效，key:" + key);
                unValidCache.add(value);
            } else {
                set.add(key);
            }
        }
        try {
            return joinPoint.proceed();
        } finally {
        }
    }


}
